/*->c.vtact */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"



#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.pr"

#include "h.term"
#include "h.tek"

#include "h.vxdef"
#include "h.vxwimp"
#include "h.vxterm"

#include "h.vtdef"
#include "h.vtscr"
#include "h.vtcon"
#include "h.vtsend"
#include "h.vtprint"
#include "h.vtwimp"
#include "h.vtkey"
#include "h.vtlo"
#include "h.vtcol"
#include "h.vtchar"


#include "h.vtact"



/***************************************************************************/
/*
 Code to handle byte input to VT terminals
*/
/***************************************************************************/



void inner_set()
{
 int i;
 for(i=0;i<32;i++) inner_stack[i]=inner_prefix[i]=0;
 inner_par=0;
 inner_char=0;
 inner_query=0;
 inner_tot=0;
}


void flagset(void)
{
 inner_set();
 bra_flag=0;
 escflag=0;
 curly=0;
 curlypc=0;
 hash=0;
 percent=0;
}


void vt220esc(int byte)
{
 if(vt220) switch(byte)
   {
     case '~': /* lock G1 -> GR */
               vtgr=1;
               break;

     case 'n': /* lock G2 -> GL */
               vtgl=2;
               break;

     case '}': /* lock G2 -> GR */
               vtgr=2;
               break;

     case 'o': /* lock G3 -> GL */
               vtgl=3;
               break;

     case '|': /* lock G3 -> GR */
               vtgr=3;
               break;

     case 'N': /* single shift G2->Gl */
               vtssg2=1;
               break;

     case 'O': /* single shift G3->GL */
               vtssg3=1;
               break;

     case ' ': escflag=1;
               break;

     case 'F': c1codes=0;
               break;

     case 'G': c1codes=1;
               break;

     case 'P': 
               dcsst(DCSDCS);
               break;

     case'\\': 
               dcsst(DCSST);
               break;

     case ']':
               dcsst(DCSOSC);
               break;

     case '^':
               dcsst(DCSPM);
               break;

     case '_':
               dcsst(DCSAPC);
               break;
   }
}



void esccodes(int byte)
{
 escflag=0;

 switch(byte)
 {
  case '[':
           bra_flag=1;
           inner_set();
           break;

  case 'D': /* index - cursor down scroll */
           index();
           break;

  case 'E': /* down+cr scroll scroll zone */
           index();
           carriagereturn();
           break;

  case 'H': /* set tab */
           if(!vtlock) settab();
           break;

  case 'M': /* reverse index - cursor up scroll */
           reverseindex();
           break;

  case 'Z': /*report device attributes*/
           sendatt();
           break;

  case '7': /* save cursor graphic + cset */
           savecursor();
           break;

  case '8': /* restore cursor graphic + cset*/
           loadcursor();
           break;

  case '=': /*enter keypad application mode*/
           keypadmode=1;
           break;

  case '>':   /*enter keypad numeric mode */
           keypadmode=0;
           break;

  case 'a':
           if(ttns) clearscrhome(VTFXNONE);
           break;

  case 'c':    /*terminal reset*/
           if(ttns)
           {
            vxsetfocusfront();
            viewcls();
           }
           else
           {
            vthardboot();
            clearscrhome(VTFXNONE);
           }
           break;

  case '(':
  case ')': 
  case '*':
  case '+':
  case '-':
  case '.':
  case '/':
           curly=byte;
           curlypc=0;
           break;

  case '#': 
           hash=1;
           break;

  case '%':
           if(tekopen && tektextplane) percent=1;
           break;

   default:
           vt220esc(byte);
           break;
 }
}





void innerpercent(int byte)
{
 if(byte=='!' && percent==1) percent++;
 else
 if(byte=='0' && percent==2)  /* go Tek mode */
 {
  vtentertekmode();
  percent=0;
 }
 else percent=0;
}





void innerhash(int byte)
{
 switch(byte)
 { 
   case  '0':
             if(ttns)
             {
              vxsetfocusfront();
              viewcls();
             }
             break;
   case  '3': /*double height top */
             setattrib(1);
             break;
   case  '4': /*double height bot */
             setattrib(2);
             break;
   case  '6': /*double width */
             setattrib(3);
             break;
   case  '5': /*single width */
             setattrib(0);
             break;
   case  '7':
             if(ttns) clearscrhome(VTFXNONE);
             break;
   case  '8': /* fill screen with E's */
             screentest();
             break;
 }
 hash=0;
}




void setrendition(int command)
{
 int temp;

 if(command==0)
 {
  rendition=0;
  foreground=WHITE;
  background=BLACK;
  if(autoprint) gorendition(rendition);
 }
 /* 1 bold */
 /* 2 faint on */
 /* 3 italic on */
 /* 4 underline */
 /* 5 blink */
 /* 6 rapid blink on */
 /* 7 reverse  */                       
 /* 8 concealed on */

 /* 22 bold off */
 /* 24 underline off */
 /* 25 blink off */
 /* 27 inverse off */

 else if(command<9)
 {
  if(command==7 && !(rendition & 0x40))
  {
   temp=background;
   background=foreground;
   foreground=temp;
  }
  if(command<3) rendition=rendition & 0xFC;
  rendition=rendition | (1 << (command-1));

  if(autoprint) gorendition(rendition);
 }

 else if(vt220 && command>20 && command<29)
 {
  switch(command)
  {
   case 22: /* bold off */
           rendition &=0xFFFE;
           break;

   case 24: /* underline off */
           rendition &=0xFFF7;
           break;

   case 25: /* blink off */
           rendition &=0xFFCF;
           break;

   case 27: /* inverse off */
           if(rendition & 0x40)
           {
            temp=background;
            background=foreground;
            foreground=temp;
           }
           rendition &=0xFFBF;
           break;
  }
  if(autoprint) gorendition(rendition);
 }


 else if(ansisys)
 {
  /* --------------------- */
  /*        ANSI-BBS       */
  /* 30 black foreground   */
  /* 31 red   foreground   */
  /* 32 green foreground   */
  /* 33 yellow foreground  */
  /* 34 blue foreground    */
  /* 35 magenta foreground */
  /* 36 cyan foreground    */
  /* 37 white foreground   */
  /* 40 black background   */
  /* 41 red background     */
  /* 42 green background   */
  /* 43 yellow background  */
  /* 44 blue background    */
  /* 45 magenta background */
  /* 46 cyan background    */
  /* 47 white background   */
  /* 48 subscript          */
  /* 49 superscipt         */

  if(command>29 && command <38) foreground=command-30;
  else 
  if(command>39 && command <48) background=command-40;
 }

 setstylec();
}



/* ?5 enter autoprint */
/* ?4 exit autoprint */
/* 5 enter printer controller */
/* 4 exit printer controller */
/* 0 print screen */
/* 1 print cursor line */

void printercommand(int command,int query)
{
 switch(command)
  {
   case 0:if(printer) printscreen();
          break;

   case 1:if(printer) printcursor();
          break;

   case 4:
          if(query) setprint(&autoprint,0);
          else      setprint(&conoprint,0);
          break;

   case 5:
          if(query) setprint(&autoprint,1);
          else            
          {
           setprint(&conoprint,1);
           printconboot();
          }
          break;
  }
}



void statusreports(int command,int query)
{
 if(command==5)  /* 5 status ? */
       sendstatusok();
 else 
 if(command==6)  /* 6 cursor posn.   */
       sendcursorposn();
 else 
 if(command==15)  /* ?15 printer status */
       sendprintstatus();
 else 
 if(command==25 && query) 
       sendlockstatus();
 else
 if(command==26 && query)
       sendkbdialect();
}



void setmodes(int command,int query)
{
 if(!query) 
   switch(command) 
    {
     case  2: /* 2 keyboard locked */
            if(!vtlock) keylockmode=1;
             break;

     case  3: /* unset debug display */
             concode=TERMEXECCTRLS;
             break;

     case  4: /* 4 insert mode */
             insertmode=1;
             break;

     case 12: /* 12 local echo off */
             echomode=0;
             break;

                             
     case 20: /* 20 new line mode on */
             newlinemode=1;
             break;
    }

else
   switch(command)
    {
                            
     case  1: /* 1 cursor key application mode */ 
             cursorkeymode=0;
             break;
                            
     case  2: /* 2 no set mode */
             break;
                            
     case  3: /* 3 132 col mode */
             go132();
             break;
                             
     case  4: /* 4 smooth scroll */
             if(!vtlock) smooth=1;
             break;
                            
     case  5: /* 5 screen reverse */
             if(!vtlock) screenm(1);
             break;
                             
     case  6: /* 6 origin mode relative */
             setoriginmode();
             break;
           
     case  7: /* 7 autowrap on */
             wrapmode=1;
             break;
                             
     case  8: /* 8 autorepeat on */
             if(!vtlock) setauto(automode=1);
             break;
                             
     case  9: /* 9 interlace on */
             break;
                             
     case 18: /* 18 print form feed on */
             printff=1;
             break;
                             
     case 19: /* 19 print area full screen */
             printarea=1;
             break;

     case 25:
             vtcurs=1;
             break;

     case 38:
             if(tekopen) teksetfocusfront();
             break;

     case 42: /* set ncs 320 */
             if(vt220) /* force nrc into g0-g3, disable 8 bits */
             {
              vtgn[0]=vtgn[1]=vtgn[2]=vtgn[3]=vtncs;
              c1codes=0;
             }
             break;

     case 66: /* keypad==application 320 */
             if(vt220) keypadmode=1;
             break;

     case 67: /* set == don't swop bs and del */
             if(vt220) vtswopbs=0;
             break;
    }
}




void resetmodes(int command,int query)
{
 if(!query) 
   switch(command)
   {
                             
    case  2: /*  2 keyboard unlocked  */
            if(!vtlock) keylockmode=0;
            break;


     case  3: /* debug display */
             concode=TERMDISPCTRLS;
             break;

                             
    case  4: /*  4 replace mode       */
            insertmode=0;
            break;
                             
    case 12: /*  12 local echo on     */
            echomode=1;
            break;
                             
    case 20: /*  20 new line mode off */
            newlinemode=0;
            break;
   }
 else
   switch(command) 
   {
                             
    case  1: /*  1 cursor key cursor mode */
            cursorkeymode=1;
            break;

    case  2: /*  2 VT52 mode              */
            ansimode=0;
            break;

    case  3: /*  3 80 col mode        */
            go80();
            break;

                            
    case  4: /*  4 jump scrolling     */
            if(!vtlock) smooth=0;
            break;
                             
    case  5: /*  5 screen normal      */
            if(!vtlock) screenm(0);
            break;
                            
     case  6: /*  6 origin mode absolute */
             resetoriginmode();
             break;
                             
     case  7: /*  7 autowrap off */
             wrapmode=0;
             break;
                             
     case  8: /*  8 auto repeat off */
             if(!vtlock) setauto(automode=0);
             break;
                             
     case  9: /*  9 interlace off */
             break;
                        
     case 18: /* 18 print form feed off */
             printff=0;
             break;
                             
     case 19: /* 19 print area scroll zone */
             printarea=0;
             break;

     case 25:
             vtrefreshcursor();
             vtcurs=0;
             break;

     case 42: /* unset ncs */
             c1codes=1;
             break;

     case 66: /* keypad==numeric 320 */
             if(vt220) keypadmode=0;
             break;

     case 67: /* unset == swop bs and del */
             if(vt220) vtswopbs=1;
             break;
   }
}



void escseq(int byte)
{
 int i;
 int top;
 int topp;
 int next;

 top=inner_stack[0];
 if(top==0) topp=1;
 else       topp=top;
 next=inner_stack[1];

 switch(byte)
 {
  case '@': /* insert a number of spaces treat 0 as 1 */
            /* do not move cursor */
           insertspc(topp);
           break;

  case 'A': /*  cursor up      */
           cursorup(topp);
           break;

  case 'B': /*  cursor down    */
           cursordown(topp);
           break;

  case 'C': /*  cursor forward */
           cursorforward(topp);
           break;

  case 'D': /*  cursor back  treat 0 as 1 no wrapping */
           cursorback(topp);
           break;

  case 'E': /* next line - index topp times 320 */
           if(vt220) indexn(topp);
           break;

  case 'F': /* previous line - reverse index topp times 320 */
           if(vt220) reverseindexn(topp);
           break;

  case 'G': /* ANSI cursor to absolute column */

           break;


  case 'f': /*  set cursor position */
  case 'H': /*  also set  tab ? */
           cursorxy(next-1,topp-1);
           break;      

  case 'I': /* tab topp times 320 */
           if(vt220) dotab(topp);
           break;


  case 'J': /*  erase in display   */
            /* nb reset atribs on any line */

           if(!ansisys) i=inner_query?VTSELER:VTFXNONE;
           else         i=VTFXNONE;

           if(top==0) /*erase from here to end of screen   */
                      eraseeop(i);
           else
           if(top==1) /*erase from start of screen to here */
                      erasesop(i);
           else
           if(top==2) /* clear entire screen */
                      {
                       if(ansisys) clearscrhome(i);
                       else        clearscr(i);
                      }
           break;

  case 'K': /*  erase in line      */
            /* nb do not reset attributes */

           if(!ansisys) i=inner_query?VTSELER:VTFXNONE;
           else         i=VTCBACK;

           if(top==0) /*erase from here to end of line */
                      eraseeol(i);
           else
           if(top==1) /*erase from start of line to here */
                      erasesol(i);
           else
           if(top==2) /*erase entire line */ 
                      eraseline(i);
           break;


  case 'L': /* insert lines  treat 0 as 1 */
            /* shuffle down - do not move cursor */
           insline(topp);
           break;

  case 'M': /* delete lines treat 0 as 1 */
            /* shuffle up - do not move cursor */
           delline(topp);
           break;

  case 'P': /* delete a number of chars treat 0 as 1 */
            /* do not move cursor */
           delspc(topp);
           break;

  case 'X':
           if(vt220) setspc(topp);
           break;


  case 'a': /* ANSI cursor forward pn columns */
           break;


  case 'c': /*  report device attributes */
           if(currentterminal==TERMVT220 && inner_char=='>') sendatt220();
           else                                              sendatt();
           break;


  case 'd': /* ANSI cursor to row pr absolute */
           break;

  case 'e': /* ANSI cursor down pn columns */
           break;


  case 'g': /*  clear tabs     */
           if(!vtlock)
           {
            if(top==0) /*  0 clear current */
                        cleartab();
            else
            if(top==3) /*  3 clear all */
                       clearalltabs();
           }
           break;

  case 'h': /*  set modes            */
           for(i=0;i<=inner_par;i++) setmodes(inner_stack[i],inner_query);
           break;

  case 'i': /* printer commands */
           printercommand(top,inner_query);
           break;

  case 'l': /* reset modes */
           for(i=0;i<=inner_par;i++) resetmodes(inner_stack[i],inner_query);
           break;

  case 'm': /*  graphics rendition */
           for(i=0;i<=inner_par;i++)
           {
            if(tekopen)
            {
             if(inner_prefix[i]==0) setrendition(inner_stack[i]);
            }
            else        setrendition(inner_stack[i]);
           }
           break;

  case 'n': /*  device status report */
           statusreports(top,inner_query);
           break;

  case 'p': /* vt220 modes */
           if(inner_char=='!')
           {
            vtsoftboot();
           }
           else
           if(inner_char=='"')
           {
            if(top==61) vt220=0;
            else 
            if(top==62 || top==63)
             {
              if(currentterminal==TERMVT220) vt220=1;
              if(next==0 || next==2) c1codes=1;
              else 
              if(next==1)            c1codes=0;
             }
            vtsoftboot();
           }
           else
           if(inner_char=='$')
           {
            if(inner_query)
            {
             vtreportansimode(topp);
            }
            else
            {
             vtreportdecmode(topp);
            }
           }
           break;

  case 'q': /* LED commands */
            /* 0 = all off  */
            /* Ps = led Ps on */
           if(vt220 && inner_char=='"')
           {
            /* erasable stuff */ 
            selerase=(top==1);
           }
           else
           for(i=0;i<=inner_par;i++)
           {
            if(inner_stack[i]==0) ledsoff();
            else                  ledon(inner_stack[i]);
           }
           break;

  case 'r': /*  set margins        */
           if(inner_par<1 || next==0) next=24;
           setmargins(topp-1,next-1);
           break;

  case 's':
           if(ansisys) savecursor();
           break;

  case 'u':
           if(vt220)
           {
            if(inner_char=='$' && top==1) sendterminalstate();
            else
            if(inner_char=='&') vtsendupss();
           }
           else
           if(ansisys) loadcursor();
           break;

  case 'w':
           if(vt220 && inner_char=='$')
           {
            if(top==2) vtsendtabs();
            else
            if(top==1) vtsendcursorinforeport();
           }
           break;

  case 'x': /* terminal paramters */
            /* 0 request send on end of setup */
            /* 1 request send only on request */
           sendterminalparams();
           break;

  case 'y': /*test  2;Ps y invoke test Ps */
           vtexitstatusline();
           break;

  case '~': /* select status line type 0==none 1==local 2== host */
           vtexitstatusline();
           if(inner_char=='$') vtsetstatusline(top);
           break;

  case '}':
           if(inner_char=='$') 
           {
            if(top==0) vtexitstatusline();
            else       vtenterstatusline();
           }
           break;

 }

 bra_flag=0;
}



void bracodes(int byte)
{
 if(byte>='0' && byte <='9')
  {
   inner_tot=inner_tot*10+(byte-'0');
   return;
  }

 if(!inner_query && byte=='?')
  {
   inner_query=1;
   return;
  }

 inner_stack[inner_par]=inner_tot;
 if(byte==';')
  {
   inner_par+=(inner_par!=31);
   inner_tot=0;
   inner_prefix[inner_par]=0;
   return;
  }

 switch(byte)
  { 
   case  ' ':
   case  '!': 
   case  '#':
   case  '$':
   case  '%':
   case  '&':
   case '\'':
   case  '(':
   case  ')':
   case  '*':
   case  '+':
   case  ',':
   case  '-':
   case  '.':
   case  '/':
   case  '"':
   case  '>':
             inner_char=byte;
             inner_prefix[inner_par]=byte;
             return;
  }


 if(tekopen && (byte=='<' || byte=='='))
 {
  inner_prefix[inner_par]=byte;
  return;
 }

 escseq(byte);
}







/* assign charcter set with ident to gn */

void curlyset(int ident,int gnn,int size)
{
 int cset;

 switch(ident)
 {
  case '@'|256:
           if(vt220)  cset=VTDRCS;
           break;

  case 'A':
           if(vt220)
           {
            /* cset=VTLATIN1; */

            if(vtcsetmap[VTUK].size==size) cset=VTUK;
            else                           cset=VTLATIN1;
           }
           else       cset=VTUK;
           break;

  case 'B':
           cset=VTASCII;
           break;

  case '4':
           cset=VTDUTCH;
           break;

  case '5':
  case 'C':
           cset=VTFINNISH;
           break;

  case 'R':
           cset=VTFRENCH;
           break;

  case '9':
  case 'Q':
           cset=VTFRENCHCANADIAN;
           break;

  case 'K':
           cset=VTGERMAN;
           break;

  case 'Y':
           cset=VTITALIAN;
           break;

  case '`':
  case 'E':
  case '6':
           cset=VTNORWEGIAN;
           break;

  case '6'|128:
           cset=VTPORTUGESE;
           break;

  case 'Z':
           cset=VTSPANISH;
           break;

  case '7':
  case 'H':
           cset=VTSWEDISH;
           break;

  case '=':
           cset=VTSWISS;
           break;

  case '<':
           cset=vtupss;
           break;

  case '>':
           cset=VTTECH;
           break;

  case '0':
           cset=VTSPECGR;
           break;

  case '1':
           cset=VTALT;
           break;

  case '2':
           cset=VTALTGR;
           break;

  case '5'|128:
           cset=VTSUPPGR;
           break;

   default:                    /* do nothing */
           return;
 }

/* if(vtcsetmap[cset].size==size) */ vtgn[gnn]=cset;
}






void curlycodes(int byte)
{
 if(!curlypc && byte=='%')
 {
  curlypc=128;
 }
 else
 if(!curlypc && byte==' ')
 {
  curlypc=256;
 }
 else
 {
  switch(curly)
  {
   case '(':                                   /* G0 */
            curlyset(byte | curlypc,0,94);
            break;

   case ')':                                   /* G1 */
            curlyset(byte | curlypc,1,94);
            break;

   case '*':                                   /* G2 */
            curlyset(byte | curlypc,2,94);
            break;

   case '+':                                   /* G3 */
            curlyset(byte | curlypc,3,94);
            break;

   case '-':                                   /* G1 96 */
            curlyset(byte | curlypc,1,96);
            break;

   case '.':                                   /* G2 96 */
            curlyset(byte | curlypc,2,96);
            break;

   case '/':                                   /* G3 96 */
            curlyset(byte | curlypc,3,96);
            break;
  }

  curly=curlypc=0;
 }
}



/*****************************************************************************/


void vtbyte(int byte)
{
 if(!ansimode) vt52(byte);
 else
 if(byte<32)   concodes(byte);
 else
 if(bra_flag)  bracodes(byte);
 else
 if(escflag)   esccodes(byte);
 else
 if(curly)     curlycodes(byte);
 else
 if(hash)      innerhash(byte);
 else
 if(percent)   innerpercent(byte);
 else
 if(byte<128 || ((ansisys || vt220) && byte <256)) printable(byte);
}



int vtmaskbyte(int byte)
{
 if((!vt220 || !bit8c) && !ansisys) byte=byte & 0x7F;
 return(byte);
}



void vt220byte(int byte)
{
 if((!vt220 || !bit8c) && !ansisys) byte=byte & 0x7F;
 
 if(conoprint) printcontroller(byte);
 else
 if(!vt220) vtbyte(byte);
 else
 if(byte<128 || byte>159) vtbyte(byte); 
 else 
 {
  vtbyte(27);
  vtbyte(byte-64);
 }
}

